java导出PDF文件(插入图片,表格,字体)
业务需求:需要根据系统里的各种数据动态生成PDF会议材料。
最终呈现图
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210206131536304.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1RUQzA2MDU=,size_16,color_FFFFFF,t_70)
思路
因为会议材料涉及各种数据,图片。同时还要有表格及字体样式的要求,所以需要用每一页要用对应的模板来生成PDF. 所以第一步:用HTML页面绘制出每页的样式,然后改后缀将”.html“,换成”.ftl“,这样就完成FTL模板的转换,这里要注意的是,CSS样式的版本,因为后面我们要用freemark语法将数据写入到ftl模板中,而freemark语法有很多不支持高版本的CSS样式。所以最好用CSS低版本的。可以多试试。 第二步:freemark语法将数据写入到ftl模板中生成html页面。这里注意的是图片的插入和字体样式(代码中可以自己看) 第三步:将所有生成的html页面转换成PDF。 第四步:将所有生成的PDF合成一个PDF文件
注意:1、不用担心PDF文件中每页的顺序问题,这个是根据你的ftl模板的读取顺序来的。 2、这个html文件转PDF时候是不会自动换行的。这个网上有很多材料可以自己查,简单来说就是这个jar包是外国人开发的,支持英文空格换行。所以中文换行的话需要自己写方法。或者改JAR包,我水平不够,所以自己写方法实现的,就是有些麻烦,代码块中有。
资源目录
这里需要建一个资源目录,存放你的图片 和字体以及模板文件
字体,这俩个是黑体和宋体 模板文件(模板的文件名要和代码里面对应) 图片(PDF背景图也放这) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210206125457277.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1RUQzA2MDU=,size_16,color_FFFFFF,t_70) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210206125506324.png)
JAR包,这里需要itex5的jar包
你可以自己下,百度搜,这里就不多加赘述了 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210206125910668.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1RUQzA2MDU=,size_16,color_FFFFFF,t_70)
下面就代码部分
第一个class是业务部分,
package com.ttc.pdf;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.io.output.FileWriterWithEncoding;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import freemarker.template.Configuration;
import freemarker.template.Template;
public class Atest {
// 统计 生成html 页数
public final static ThreadLocal pageNum = new ThreadLocal();
public void exportResPdfSrv() {
// 初始值为0
pageNum.set(0);
try {
// 本地测试路径 请勿提交
String destFileName = "D:\\fbPDFRES";
String temporaryPath = destFileName + "\\fbFtl\\";// 获取ftl模板路径 和html及pdf临时生成文件路径
String imgPath = destFileName + "\\fbImgs\\";// 获取图片路径
String fontPath = destFileName + "\\fbFont\\";// 获取字体路径
String pdfPath = destFileName + "\\savePath\\";// 保存路径
// 删除目录下所有非后缀名为 ftl文件
this.deleteFiles(temporaryPath, FbExportPDFUtils.PDF_FTL);
// 生成pdf
this.createAllHTML(temporaryPath);
// 获取目录下所有html文件路径
List htmlFiles = getFiles(temporaryPath, FbExportPDFUtils.PDF_HTML);
for (int i = 0; i < htmlFiles.size(); i++) {
String num = htmlFiles.get(i).substring(htmlFiles.get(i).indexOf("-") + 1,
htmlFiles.get(i).indexOf("."));
String PdfFileName = temporaryPath + UUID.randomUUID().toString().replace("-", "").toLowerCase() + "-"
+ num + FbExportPDFUtils.PDF_PDF;
// 生成pdf文件
prodPdfByHtmlNext(PdfFileName, htmlFiles.get(i), imgPath, fontPath);
}
// 获取目录下所有pdf文件路径
List pdfFiles = getFiles(temporaryPath, "pdf");
SimpleDateFormat sdf = new SimpleDateFormat("MMddHHmmss");
// 物理子系统系统中文名称(英文简称)
String cname = "支付结算系统";
// 日期(年月日)_工单号+**系统汇报材料
String savePath = pdfPath + sdf.format(new Date()) + cname + FbExportPDFUtils.PDF_PDF;
// 合成pdf
this.morePdfToPdf(pdfFiles, savePath);
// 删除目录下所有非后缀名为 ftl文件
this.deleteFiles(temporaryPath, FbExportPDFUtils.PDF_FTL);
} catch (Exception e) {
System.out.print("PDF导出异常:" + e);
e.printStackTrace();
}
}
/**
* 生成所有PDF
*
* @param srPo
* @param temporaryPath
*/
private void createAllHTML(String temporaryPath) {
try {
// 生成第一页html
Map mapOneData = this.getOnePaddingData();
this.exportFtlToHtml(mapOneData, FbExportPDFUtils.PDF_ONE_PAGE, temporaryPath);
// 生成第二页html
Map maptwoData = new HashMap();
maptwoData.put("fbPageNumbers", 2);
this.exportFtlToHtml(maptwoData, FbExportPDFUtils.PDF_TWO_PAGE, temporaryPath);
// 生成第三页html
Map mapThreeData = this.getThreePaddingData();
this.exportFtlToHtml(mapThreeData, FbExportPDFUtils.PDF_THREE_PAGE, temporaryPath);
// 生成第四页html
Map mapFourData = this.getFourPaddingData();
this.exportFtlToHtml(mapFourData, FbExportPDFUtils.PDF_FOUR_PAGE, temporaryPath);
// 生成第五页html
Map mapFiveData = this.getFivePaddingData();
this.exportFtlToHtml(mapFiveData, FbExportPDFUtils.PDF_FIVE_PAGE, temporaryPath);
// 生成第六页html 根据数据量显示 可能会多页
List mapSixData = this.getSixPaddingData();
// 每页总条数
int sixPageSize = 5;
this.dataListPagingToPDF(mapSixData, temporaryPath, FbExportPDFUtils.PDF_SIX_PAGE, sixPageSize);
// 生成第八页html 提请会议审议的主要关注点
Map mapEightData = this.getEightPaddingData();
Boolean isShowFlag = (Boolean) mapEightData.get("isShowFlag");
if (isShowFlag) {
mapEightData.put("fbPageNumbers", pageNum.get() + 1);
this.exportFtlToHtml(mapEightData, FbExportPDFUtils.PDF_EIGHT_PAGE, temporaryPath);
}
// 生成第九页html
Map mapNineData = new HashMap();
mapNineData.put("fbPageNumbers", pageNum.get() + 1);
this.exportFtlToHtml(mapNineData, FbExportPDFUtils.PDF_NINE_PAGE, temporaryPath);
// 生成第十一页html
List elevenData = this.getImageList();
this.generateImgToHtml(FbExportPDFUtils.FBPDF_APP_IMG_KEY, FbExportPDFUtils.PDF_ELEVEN_PAGE, temporaryPath,
elevenData);
// 生成第十五页html
Map mapFifteenData = this.getFifteenPaddingData();
Boolean fifteenIsShowFlag = (Boolean) mapFifteenData.get("isShowFlag");
if (fifteenIsShowFlag) {
this.exportFtlToHtml(mapFifteenData, FbExportPDFUtils.PDF_FIFTEEN_PAGE, temporaryPath);
}
} catch (Exception e) {
System.out.println("查询数据和生成HTML异常 " + e);
e.printStackTrace();
}
}
private List getImageList() {
List list = new ArrayList();
list.add(new ImagePo("1", "1-1.jpg", "aaa"));
list.add(new ImagePo("2", "2-1.jpg", "ss"));
list.add(new ImagePo("3", "3-1.jpg", "vcc"));
return list;
}
/**
* 生成文件名
*
* @param srId
* @param cname
* @return
*/
public String createFileName(String srId, String cname) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
return sdf.format(new Date()) + "_" + srId + "_" + cname + "系统审核专题会汇报材料.pdf";
}
public void createFbCheckIdea(String srId, String operType, String nodeName, String temporaryPath, String fileName,
String CZCode) {
Map dataTemp = this.getCommonData();
this.exportFtlToHtml(dataTemp, fileName, temporaryPath);
}
/**
* ftl模板转html文件
*
* @param dataMap 模板填充数据
* @param ftlFileName 模板名
*/
public void exportFtlToHtml(Map dataMap, String ftlFileName, String ftlPath) {
pageNum.set(pageNum.get() + 1);
System.out.println("开始生成:" + pageNum.get() + " html");
System.out.println(dataMap.toString());
// 用ftl模板生成html
Configuration configuration = new Configuration();
FileWriterWithEncoding out = null;
try {
configuration.setDirectoryForTemplateLoading(new File(ftlPath));
//字符集
configuration.setDefaultEncoding(FbExportPDFUtils.ENCODING);
Template template = configuration.getTemplate(ftlFileName);
//html文件名字
String htmlFileName = ftlPath + UUID.randomUUID().toString().replace("-", "").toLowerCase() + "-"
+ pageNum.get() + ".html";
System.out.println("生成 : " + htmlFileName);
out = new FileWriterWithEncoding(new File(htmlFileName), FbExportPDFUtils.ENCODING);
//将数据和模板合成
template.process(dataMap, out);
out.close();
System.out.println("生成:" + pageNum.get() + " html成功");
} catch (Exception e) {
System.out.println("ftl模板转html文件异常:" + e);
e.printStackTrace();
} finally {
if (null != out) {
try {
out.close();
} catch (Exception e) {
System.out.println("ftl模板转html文件out关闭异常:" + e);
}
}
}
}
/**
* html转pdf
* 核心代码
* @param pdfFilePath pdf生成路径
* @param htmlPath html生成路径
* @return
*/
public boolean prodPdfByHtmlNext(String pdfFilePath, String htmlPath, String imgAndFontPath, String fontPath) {
boolean bReturn = false;
OutputStream outputStream = null;
BufferedReader bufferedReader = null;
try {
outputStream = new FileOutputStream(pdfFilePath);
// 读取html文件
StringBuffer demoHtml = new StringBuffer();
bufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream(htmlPath), FbExportPDFUtils.ENCODING));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
demoHtml.append(line);
}
String html = demoHtml.toString();
ITextRenderer renderer = new ITextRenderer();
// 设置字体 arialuni.ttf 需与html模板样式 body {font-family:Arial Unicode MS;}一致 否者不显示中文
ITextFontResolver fontResolver = renderer.getFontResolver();
// 遍历字体
File[] listFiles = new File(fontPath).listFiles();
for (int i = 0; i < listFiles.length; i++) {
System.out.println("fontPath:" + listFiles[i].toString());
fontResolver.addFont(listFiles[i].toString(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
}
//将html文件转换
renderer.setDocumentFromString(html);
// 解决图片的相对路径问题,图片路径必须以file:/开头
renderer.getSharedContext().setBaseURL("file:" + imgAndFontPath);
renderer.layout();
renderer.createPDF(outputStream);
outputStream.flush();
renderer.finishPDF();
bReturn = true;
} catch (Exception e) {
System.out.println("html转pdf :" + e);
} finally {
if (null != bufferedReader) {
try {
bufferedReader.close();
} catch (Exception e) {
System.out.println("html转pdf未正常关闭: bufferedReader :" + e);
}
}
if (null != outputStream) {
try {
outputStream.close();
} catch (Exception e) {
System.out.println("html转pdf未正常关闭: outputStream:" + e);
}
}
}
return bReturn;
}
/**
* 第一页数据
*
* @param srPo
*/
private Map getOnePaddingData() {
Map mapOneData = new HashMap();
mapOneData.put("systemName", "测试系统");
return mapOneData;
}
/**
* 填充第三页数据--基本信息
*
* @param srPo
*/
public Map getThreePaddingData() {
System.out.println("生成第3页ppt对应参数");
Map mapTable = new HashMap();
;
try {
mapTable.put("cname", "啊啊啊");//
mapTable.put("appSystemCode", "水水水水");//
mapTable.put("logicAppCname", "顶顶顶顶顶"); //
mapTable.put("logicAppCode", "帆帆帆帆"); //
mapTable.put("isPlanInYear", "灌灌灌灌");
mapTable.put("projectName", "1111无误");
mapTable.put("projectNum", "嗡嗡嗡");
mapTable.put("projectProposer", "强强强强");
mapTable.put("projectOperate", "日日日日");
mapTable.put("itLine", "涛涛涛涛");
mapTable.put("projectType", "有有有由于");
mapTable.put("projectScale", "英语u");
mapTable.put("developType", "永远永远");
mapTable.put("projectStage", "广告广告和");
mapTable.put("urgencyDegree", "急急急急急急");
mapTable.put("rrinfoType", "看看看看");
mapTable.put("isCompleteTest", "啦啦啦啦啦");
mapTable.put("dataCenterArea", "看看看看");
mapTable.put("dataCenterPrincipal", "咩咩咩咩吗");
mapTable.put("fbPageNumbers", pageNum.get() + 1);
System.out.println("第三页ppt参数" + mapTable.toString());
} catch (Exception e) {
System.out.println("第三页ppt参数异常:" + e);
}
return mapTable;
}
/**
* 第四页数据
*/
private Map getFourPaddingData() {
Map mapFourData = new HashMap();
mapFourData.put("caseDescribe", "啊啊啊十大阿斯顿撒旦打撒反对反对地方撒大师傅犯得上地方撒");
mapFourData.put("sysFond", "水水低调的风格对方的和规范化规范化和规范水");
mapFourData.put("sysTarget", "烦烦烦方的手法对付敌方导很广泛化工的方法的规划官方的宏观环境弹法");
mapFourData.put("fbPageNumbers", pageNum.get() + 1);
return mapFourData;
}
/**
* 将带有图片的ftl模板转成html
*
* @param imgParameter ftl模板里 图片参数
* @param ftlName 对应模板
* @param temporaryPath 生成html路径
* @param fbList 图片集合
*/
public void generateImgToHtml(String imgParameter, String ftlName, String temporaryPath, List fbList) {
for (int i = 0; i < fbList.size(); i++) {
Map mapTable = new HashMap();
ImagePo po = (ImagePo) fbList.get(i);
String attName = po.getName();
String[] tempStrAry = attName.split("-");
System.out.println("a@@@@@" + tempStrAry[1]);
mapTable.put("imgParame", tempStrAry[1]);
mapTable.put(imgParameter, attName);
// 页码
mapTable.put("fbPageNumbers", pageNum.get() + 1);
this.exportFtlToHtml(mapTable, ftlName, temporaryPath);
}
}
/**
* 获取目录下对应后缀的 文件路径集合
*
* @param filePath 目录
* @param fileSuffix 文件名后缀
*/
public List getFiles(String filePath, String fileSuffix) {
List list = new ArrayList();
File file = new File(filePath);
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {
if (files[i].toString().endsWith(fileSuffix)) {
list.add(files[i].toString());
System.out.println("htmlPath: " + files[i].toString());
}
}
}
Collections.sort(list, new Comparator() {
@Override
public int compare(String str1, String str2) {
int substring1 = Integer.parseInt(str1.substring(str1.indexOf("-") + 1, str1.indexOf(".")));
int substring2 = Integer.parseInt(str2.substring(str2.indexOf("-") + 1, str2.indexOf(".")));
if (substring1 < substring2) {
return -1;
} else if (substring1 == substring2) {
return 0;
}
return 1;
}
});
return list;
}
/**
* 将目录下pdf文件合成一个
*
* @param fileList 路径集合
* @param pdfFileName 生成pdf文件名
*/
public void morePdfToPdf(List fileList, String savePath) {
Document doc = null;
PdfReader pdfRead = null;
PdfCopy copy = null;
try {
pdfRead = new PdfReader(fileList.get(0));
doc = new Document(pdfRead.getPageSize(1));
copy = new PdfCopy(doc, new FileOutputStream(savePath));
doc.open();
for (int i = 0; i < fileList.size(); i++) {
PdfReader reader = null;
try {
reader = new PdfReader(fileList.get(i));
int pages = reader.getNumberOfPages();// 获取总页码
for (int j = 1; j 0) {
tatalPage += 1;
}
for (int pageNo = 0; pageNo < tatalPage; pageNo++) {
map = new HashMap();
int fromIndex = pageNo * pageNumber;
int toIndex = ((pageNo + 1) * pageNumber);
if (toIndex > totalCount) {
toIndex = totalCount;
}
System.out.println("第" + pageNo + "页");
List subList = list.subList(fromIndex, toIndex);
map.put("dataList", subList);
map.put("fbPageNumbers", pageNum.get() + 1);
System.out.println("数据为: " + map.toString());
this.exportFtlToHtml(map, ftlName, temporaryPath);
System.out.println("分页后:" + subList.toString());
}
}
} catch (Exception e) {
System.out.println("列表分页异常:" + e);
}
}
/**
* 公共方法
*/
private Map getCommonData() {
// 判断审核意见是否为空
Boolean flag = false;
Map mapData = new HashMap();
// 根据模板的id插入
mapData.put("a", "");
mapData.put("flag", flag);
mapData.put("fbPageNumbers", pageNum.get() + 1);
return mapData;
}
/**
* 资源
*/
private List getOtherResData() {
System.out.println("开始获取资源");
List otherResList = new ArrayList();
for (int i = 0; i < 5; i++) {
Map mapSingle = new HashMap();
mapSingle.put("duName", "N/A");
String facility = this.subStringByPX("测试长度fg123456啊啊啊", 10, FbExportPDFUtils.ENCODING);
mapSingle.put("facility", facility);
mapSingle.put("model", "安安");
mapSingle.put("config", "安安");
mapSingle.put("quantity", "安安");
mapSingle.put("purpose", "安安");
mapSingle.put("solveWay", "安安");
mapSingle.put("capacity", "其他");
mapSingle.put("site", "安安");
mapSingle.put("deliveryTime", "安安");
System.out.println("获取其资源:" + mapSingle.toString());
otherResList.add(mapSingle);
}
return otherResList;
}
private List createComResSheetRow() {
List sixDataList = new ArrayList();
for (int i = 0; i < 10; i++) {
Map mapSingle = new HashMap();
mapSingle.put("duName", "安安");
mapSingle.put("facility", "安安");
mapSingle.put("model", "安安");
mapSingle.put("config", "安安");
mapSingle.put("quantity", "安安");
mapSingle.put("purpose", "安安");
mapSingle.put("site", "安安");
mapSingle.put("solveWay", "安安");
mapSingle.put("capacity", "估算");
mapSingle.put("deliveryTime", "2020-01-01");
sixDataList.add(mapSingle);
}
return sixDataList;
}
// 递归
public String digui(String str, int bytes, String encode) {
int len;
try {
len = str.getBytes(encode).length;
if (len > bytes) {
str = str.substring(0, str.length() - 1);
str = digui(str, bytes, encode);
}
} catch (Exception e) {
System.out.println("字符串截取异常" + e);
}
return str;
}
/**
* 按字节截取字符串拼接
* 通用方法
*
* @param str
* @param bytes
* @param encode 字符集
* @return
*/
public String subStringByPX(String str, int bytes, String encode) {
String result = ""; // 每次循环截取的字符串的内容
String parameter = ""; // 最后返回的结果字符串
int i = 0; // 截取掉的字符串的总长度
int j = 0; // 截取掉的字符串的字节长总度
String ss = ""; // 减掉截取过的剩下的字符串
if (str != null) {
try {
int length = str.getBytes(encode).length;// 获取整个字符串的字节长度
while (true) {
ss = str.substring(i, str.length());
if (bytes < length - j) {
// 循环每次截取的结果
result = digui(ss, bytes, encode);
parameter += result + "";
// 截取掉的字符串字节数
j += result.getBytes(encode).length;
// 截取掉的字符串长度
i += result.length();
} else {
break;
}
}
} catch (Exception e) {
System.out.println(e);
}
// 加上截取之后后面剩余字符串
parameter += str.substring(i, str.length());
}
return parameter;
}
/**
* 删除目录下除对应后缀的 其他文件
*
* @param filePath 目录
* @param fileSuffix 文件名后缀
* @return
*/
public void deleteFiles(String filePath, String fileSuffix) {
File file = new File(filePath);
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {
String path = files[i].toString();
if (!fileSuffix.equals(path.substring(path.lastIndexOf(".") + 1))) {
files[i].delete();
}
}
}
System.out.println("临时文件已清空");
}
// 递归
public String diGuiString(String str, int bytes) {
int len;
try {
len = str.length();
if (len > bytes) {
str = str.substring(0, str.length() - 1);
str = diGuiString(str, bytes);
}
} catch (Exception e) {
System.out.println(e);
}
return str;
}
/**
* 按字节截取字符串拼接
* 通用方法
*
* @param str
* @param bytes
* @return
*/
public String subFbString(String str, int bytes) {
String result = ""; // 每次循环截取的字符串的内容
String parameter = ""; // 最后返回的结果字符串
int i = 0; // 截取掉的字符串的总长度
int j = 0; // 截取掉的字符串的字节长总度
String ss = ""; // 减掉截取过的剩下的字符串
if (str != null) {
try {
int length = str.length();// 获取整个字符串的字节长度
while (true) {
ss = str.substring(i, str.length());
if (bytes < length - j) {
// 循环每次截取的结果
result = diGuiString(ss, bytes);
parameter += result + "";
// 截取掉的字符串字节数
j += result.length();
// 截取掉的字符串长度
i += result.length();
} else {
break;
}
}
} catch (Exception e) {
System.out.println(e);
}
// 加上截取之后后面剩余字符串
parameter += str.substring(i, str.length());
}
return parameter;
}
}
第二个class是个常量,放模板文件名的
package com.ttc.pdf;
public class FbExportPDFUtils {
public static final String FBPDF_APP_IMG_KEY="frameworkImgPath";
public static final String FBPDF_DEPLOY_IMG_KEY="deployImgPath";
public static final String NAS="NAS";
public static final String SAN="SAN";
public static final String ENCODING = "UTF-8";
public static final String PDF_FTL="ftl";
public static final String PDF_HTML="html";
public static final String PDF_PDF=".pdf";
/**================== ftl模板文件名 =================*/
public static final String PDF_ONE_PAGE ="ppt-1.ftl";
public static final String PDF_TWO_PAGE ="ppt-2.ftl";
public static final String PDF_THREE_PAGE="ppt-3.ftl";
public static final String PDF_FOUR_PAGE="ppt-4.ftl";
public static final String PDF_FIVE_PAGE="ppt-5.ftl";
public static final String PDF_SIX_PAGE="ppt-6.ftl";
public static final String PDF_SEVEN_PAGE="ppt-7.ftl";
public static final String PDF_EIGHT_PAGE="ppt-8.ftl";
public static final String PDF_NINE_PAGE="ppt-9.ftl";
public static final String PDF_ELEVEN_PAGE="ppt-11.ftl";
public static final String PDF_THIRTEEN_PAGE="ppt-13.ftl";
public static final String PDF_FIFTEEN_PAGE="ppt-15.ftl";
public static final String PDF_SIXTEEN_PAGE="ppt-16.ftl";
public static final String PDF_SEVENTEEN_PAGE="ppt-17.ftl";
public static final String PDF_FOURTEEN_PAGE="ppt-14.ftl";
}
不明白的可以留言。
|